Skip to content

[codex] default Windows ARM backend runtime to x64#90

Merged
zouyonghe merged 2 commits intoAstrBotDevs:mainfrom
zouyonghe:codex/woa-x64-backend
Mar 13, 2026
Merged

[codex] default Windows ARM backend runtime to x64#90
zouyonghe merged 2 commits intoAstrBotDevs:mainfrom
zouyonghe:codex/woa-x64-backend

Conversation

@zouyonghe
Copy link
Member

@zouyonghe zouyonghe commented Mar 13, 2026

Summary

On Windows on ARM, the desktop shell currently bundles an ARM64 CPython backend by default. That works in CI when dependencies are preinstalled on the runner, but it breaks down for runtime-installed native packages on user machines because many upstream packages ship win_amd64 wheels but not win_arm64 wheels.

This change keeps the Windows ARM desktop shell native while defaulting the bundled backend runtime to x64. It also makes the runtime-selection logic depend on the intended desktop target architecture instead of the current Node process architecture, which matters when a WOA build runs under an emulated x64 Node process.

Root cause

The existing runtime mapping in scripts/prepare-resources/backend-runtime.mjs used process.arch directly, so Windows ARM builds always selected aarch64-pc-windows-msvc when the build host reported ARM64. That meant the packaged backend inherited the smaller win_arm64 Python wheel ecosystem. Optional native packages like pilk then fell back to source builds on end-user machines and failed without a matching local toolchain.

What changed

  • Default Windows ARM bundled backend runtime selection to x86_64-pc-windows-msvc
  • Add ASTRBOT_DESKTOP_WINDOWS_ARM_BACKEND_ARCH to explicitly force amd64/x64 or arm64/aarch64
  • Add ASTRBOT_DESKTOP_TARGET_ARCH so CI can pass the intended desktop target arch and avoid relying on the active Node binary arch
  • Share runtime-arch resolution between resource preparation and backend dependency installation so ARM64-specific dependency handling still works when the backend runtime is explicitly forced back to ARM64
  • Document the new env variables and pass them through the Windows build workflow
  • Add regression tests for default WOA behavior, explicit overrides, and emulated-x64-on-WOA cases

User impact

Windows ARM users still get a native desktop shell, but the packaged Python backend now prefers the broader x64 wheel ecosystem. That reduces the chance of runtime package installation failures for native-extension dependencies while preserving an escape hatch to force the legacy ARM64 backend when needed.

Validation

  • node --test scripts/backend/runtime-arch-utils.test.mjs scripts/prepare-resources/backend-runtime.test.mjs
  • pnpm test:prepare-resources

Both checks passed locally after the final commit.

Summary by Sourcery

Default the bundled backend runtime for Windows-on-ARM desktop builds to x64 while centralizing runtime-architecture resolution and wiring it through build and packaging.

New Features:

  • Introduce environment variables to control desktop target architecture and Windows ARM backend runtime architecture for bundled Python.

Enhancements:

  • Centralize backend runtime architecture resolution into shared utilities used by resource preparation and backend dependency installation.
  • Propagate the resolved bundled runtime architecture into the environment for downstream build steps.
  • Update the Windows desktop build workflow to pass through explicit target-arch and backend-arch overrides.
  • Document the new architecture control environment variables in the environment variables reference.

Tests:

  • Add unit tests covering bundled runtime target resolution across platforms, Windows ARM defaults, explicit overrides, invalid values, and emulated x64-on-Windows-ARM scenarios.

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@gemini-code-assist
Copy link

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request resolves a critical compatibility issue on Windows on ARM where the default ARM64 CPython backend often failed to install native packages due to a lack of win_arm64 wheels. By switching the default bundled backend runtime to x64, it significantly improves the reliability of package installations for Windows ARM users. The changes also introduce robust, explicit architecture selection mechanisms, allowing for precise control over target and backend architectures, which is vital for consistent build processes in various environments, including CI and emulation.

Highlights

  • Default Windows ARM Backend Runtime: Defaulted the bundled Python backend runtime for Windows ARM64 builds to x64 to enhance compatibility with the more prevalent win_amd64 Python wheel ecosystem, addressing issues with runtime-installed native packages.
  • Architecture Control Environment Variables: Introduced ASTRBOT_DESKTOP_TARGET_ARCH to explicitly specify the intended desktop target architecture, preventing reliance on the active Node process architecture, and ASTRBOT_DESKTOP_WINDOWS_ARM_BACKEND_ARCH to allow explicit override of the bundled backend Python architecture for Windows ARM64 builds.
  • Centralized Architecture Resolution: Centralized the logic for resolving runtime architectures into a new utility module (runtime-arch-utils.mjs), ensuring consistent architecture determination across resource preparation and backend dependency installation steps.
  • Documentation and Testing: Documented the new environment variables in docs/environment-variables.md and added comprehensive regression tests to validate default Windows ARM behavior, explicit overrides, and scenarios involving emulated x64 Node processes on Windows ARM.
Changelog
  • docs/environment-variables.md
    • Updated the document's last modification date to 2026-03-13.
    • Added ASTRBOT_DESKTOP_TARGET_ARCH to explicitly specify the desktop target architecture for resource preparation.
    • Added ASTRBOT_DESKTOP_WINDOWS_ARM_BACKEND_ARCH for overriding the bundled backend Python architecture during Windows ARM64 builds.
  • scripts/backend/build-backend.mjs
    • Imported isWindowsArm64BundledRuntime from the new runtime-arch-utils.mjs module.
    • Replaced the direct process.arch check for Windows ARM64 with the new utility function to determine if the bundled runtime is Windows ARM64.
  • scripts/backend/runtime-arch-utils.mjs
    • Added a new module to centralize and standardize desktop architecture resolution logic.
    • Defined environment variables: DESKTOP_TARGET_ARCH_ENV, WINDOWS_ARM_BACKEND_ARCH_ENV, and BUNDLED_RUNTIME_ARCH_ENV.
    • Implemented normalizeDesktopArch for validating and standardizing architecture strings (e.g., x64 to amd64).
    • Provided resolveDesktopTargetArch to determine the intended desktop target architecture, considering environment variable overrides.
    • Implemented resolveBundledRuntimeArch to determine the final bundled runtime architecture, applying Windows ARM64 specific defaults (x64) and explicit overrides.
    • Exported isWindowsArm64BundledRuntime to check if the resolved bundled runtime architecture is ARM64 on Windows.
  • scripts/backend/runtime-arch-utils.test.mjs
    • Added new unit tests for resolveBundledRuntimeArch to verify default Windows ARM64 backend runtime behavior (defaults to x64).
    • Included tests for resolveBundledRuntimeArch to ensure it honors explicit target architecture overrides, especially in emulated x64 Node environments.
    • Added tests for isWindowsArm64BundledRuntime to confirm correct behavior with explicit bundled runtime architecture handoff.
  • scripts/prepare-resources/backend-runtime.mjs
    • Imported BUNDLED_RUNTIME_ARCH_ENV and resolveBundledRuntimeArch from runtime-arch-utils.mjs.
    • Modified resolvePbsTarget to accept platform, arch, and env as parameters and utilize resolveBundledRuntimeArch for determining the normalized architecture.
    • Ensured the resolved bundled runtime architecture is set as an environment variable (BUNDLED_RUNTIME_ARCH_ENV) before proceeding with resource preparation.
  • scripts/prepare-resources/backend-runtime.test.mjs
    • Added new unit tests for resolvePbsTarget to verify that Windows ARM64 backend runtime defaults to x64.
    • Included tests to confirm resolvePbsTarget correctly handles explicit Windows ARM64 backend overrides.
    • Added tests to ensure resolvePbsTarget honors the explicit desktop target architecture when the process architecture is emulated x64.
    • Included tests to validate that resolvePbsTarget rejects invalid override values for both Windows ARM64 backend and explicit desktop target architectures.
    • Verified that resolvePbsTarget maintains correct same-architecture mappings for other platform and architecture combinations.
Ignored Files
  • Ignored by pattern: .github/workflows/** (1)
    • .github/workflows/build-desktop-tauri.yml
Activity
  • The author confirmed that all local tests, including node --test scripts/backend/runtime-arch-utils.test.mjs scripts/prepare-resources/backend-runtime.test.mjs and pnpm test:prepare-resources, passed after the final commit.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request successfully defaults the Windows on ARM backend runtime to x64, which should improve compatibility with Python's native package ecosystem. The introduction of new environment variables for architecture control, the centralization of resolution logic into a new utility module, and the addition of comprehensive unit tests are all excellent improvements. I've identified a minor robustness issue in the new utility module concerning the handling of null environment variable values, which could lead to unexpected errors. My review includes specific suggestions to address this.


export const resolveDesktopTargetArch = ({ arch = process.arch, env = process.env } = {}) => {
const overrideRaw = env[DESKTOP_TARGET_ARCH_ENV];
if (overrideRaw !== undefined && String(overrideRaw).trim()) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The current check for overrideRaw is not robust against null values. If env[DESKTOP_TARGET_ARCH_ENV] is null, overrideRaw !== undefined evaluates to true, and String(overrideRaw).trim() becomes 'null', which is a truthy string. This would cause normalizeDesktopArch to be called with null, leading to an error. Using the nullish coalescing operator (??) provides a more robust way to handle potentially null or undefined values, ensuring they are treated as empty strings and correctly ignored.

Suggested change
if (overrideRaw !== undefined && String(overrideRaw).trim()) {
if (String(overrideRaw ?? '').trim()) {

env = process.env,
} = {}) => {
const explicitBundledRuntimeArch = env[BUNDLED_RUNTIME_ARCH_ENV];
if (explicitBundledRuntimeArch !== undefined && String(explicitBundledRuntimeArch).trim()) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Similar to the previous comment, this check is not robust against null values. If explicitBundledRuntimeArch is null, it will be incorrectly processed as the string 'null'. Please use the nullish coalescing operator (??) for a more robust check that correctly handles null and undefined values.

Suggested change
if (explicitBundledRuntimeArch !== undefined && String(explicitBundledRuntimeArch).trim()) {
if (String(explicitBundledRuntimeArch ?? '').trim()) {

}

const windowsArmBackendArch = env[WINDOWS_ARM_BACKEND_ARCH_ENV];
if (windowsArmBackendArch === undefined || !String(windowsArmBackendArch).trim()) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This check for windowsArmBackendArch is also vulnerable to null values. If windowsArmBackendArch is null, the condition windowsArmBackendArch === undefined is false, and !String(windowsArmBackendArch).trim() is also false. This causes the if block to be skipped and normalizeDesktopArch to be called with null, which will fail. A more robust check is needed here as well.

Suggested change
if (windowsArmBackendArch === undefined || !String(windowsArmBackendArch).trim()) {
if (!String(windowsArmBackendArch ?? '').trim()) {

@zouyonghe zouyonghe merged commit f042973 into AstrBotDevs:main Mar 13, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant